index.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import { paths } from 'api-types'
  2. import { compact } from 'lodash'
  3. import { NextApiRequest, NextApiResponse } from 'next'
  4. import { z } from 'zod'
  5. import apiWrapper from '@/lib/api/apiWrapper'
  6. import {
  7. deleteSnippet,
  8. getSnippets,
  9. saveSnippet,
  10. SnippetSchema,
  11. updateSnippet,
  12. } from '@/lib/api/snippets.utils'
  13. const wrappedHandler = (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
  14. async function handler(req: NextApiRequest, res: NextApiResponse) {
  15. const { method } = req
  16. switch (method) {
  17. case 'GET':
  18. return handleGetAll(req, res)
  19. case 'PUT':
  20. return handlePut(req, res)
  21. case 'DELETE':
  22. return handleDelete(req, res)
  23. default:
  24. res.setHeader('Allow', ['GET', 'PUT', 'DELETE'])
  25. res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })
  26. }
  27. }
  28. type GetResponseData =
  29. paths['/platform/projects/{ref}/content']['get']['responses']['200']['content']['application/json']
  30. const getRequestParamsSchema = z.object({
  31. visibility: z.enum(['project', 'user']).optional(),
  32. name: z.string().optional(),
  33. limit: z
  34. .string()
  35. .transform((val) => Number(val))
  36. .pipe(z.number().int().positive())
  37. .optional(),
  38. cursor: z.string().optional(),
  39. sort_by: z.enum(['name', 'inserted_at']).optional(),
  40. sort_order: z.enum(['asc', 'desc']).optional(),
  41. })
  42. const handleGetAll = async (req: NextApiRequest, res: NextApiResponse<GetResponseData>) => {
  43. const result = getRequestParamsSchema.safeParse(req.query)
  44. if (!result.success) {
  45. return res.status(400).json({ data: [] })
  46. }
  47. const params = result.data
  48. // Platform specific endpoint
  49. if (params.visibility === 'project') {
  50. return res.status(200).json({ data: [] })
  51. }
  52. try {
  53. const { cursor, snippets } = await getSnippets({
  54. searchTerm: params.name,
  55. limit: params.limit,
  56. cursor: params.cursor,
  57. sort: params.sort_by,
  58. sortOrder: params.sort_order,
  59. })
  60. return res.status(200).json({ data: snippets, cursor })
  61. } catch (error) {
  62. console.error('Error fetching snippets:', error)
  63. return res.status(500).json({ data: [] })
  64. }
  65. }
  66. const handlePut = async (req: NextApiRequest, res: NextApiResponse) => {
  67. try {
  68. const updates = req.body
  69. const updatedSnippet = await updateSnippet(updates.id, updates)
  70. return res.status(200).json(updatedSnippet)
  71. } catch (error: any) {
  72. if (error instanceof Error && error.message.includes('not found')) {
  73. const body = req.body
  74. const { data, error: parseError } = SnippetSchema.safeParse(body)
  75. if (parseError) {
  76. console.error('Validation error:', parseError)
  77. return res.status(400).json({ error: parseError.message })
  78. }
  79. try {
  80. const savedSnippet = await saveSnippet(data)
  81. return res.status(200).json(savedSnippet)
  82. } catch (error) {
  83. console.error('Error creating snippet:', error)
  84. return res.status(500).json({ error: 'Failed to create snippet' })
  85. }
  86. }
  87. return res.status(500).json({ error: error?.message ?? 'Failed to update snippet' })
  88. }
  89. }
  90. const snippetIdsSchema = z
  91. .string()
  92. .transform((val) => compact(val.split(',').map((id) => id.trim())))
  93. .pipe(z.array(z.string().uuid()).nonempty())
  94. const handleDelete = async (req: NextApiRequest, res: NextApiResponse) => {
  95. const { ids } = req.query
  96. const result = snippetIdsSchema.safeParse(ids)
  97. if (!result.success) {
  98. return res.status(400).json({ error: 'Snippet IDs are required' })
  99. }
  100. const snippetIds = result.data
  101. try {
  102. for (const id of snippetIds) {
  103. await deleteSnippet(id)
  104. }
  105. res.setHeader('Content-Type', 'application/json')
  106. return res.status(200).send(snippetIds.map((id) => ({ id })))
  107. } catch (error) {
  108. console.error('Error deleting snippets:', error)
  109. return res.status(500).json({ error: 'Failed to delete snippets' })
  110. }
  111. }
  112. export default wrappedHandler